﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using GameEngine;
using EngineTest2CLR;

namespace EngineTests2
{
    /// <summary>
    /// BitBoard Converter
    /// </summary>
    public static class BitBoardConverter
    {
        /// <summary>
        /// Converts gameboard to bitboard
        /// </summary>
        public static CLRBitBoard ConvertGameBoard(GameBoard gameBoard)
        {
            CLRBitBoard cbb = new CLRBitBoard();

            for (int row = 0; row < gameBoard.Size; row++)
            {
                for (int col = 0; col < gameBoard.Size; col++)
                {
                    enumFigureType figType = gameBoard.GetField(row, col);
                    if (figType != enumFigureType.Nothing)
                    {
                        ConvertToBB(cbb, new Position(row, col), figType, gameBoard.Size / 2);
                    }
                }
            } // for

            return cbb;
        }

        /// <summary>
        /// Converts gameboard to bitboard
        /// </summary>
        public static CLRBitBoard64 ConvertGameBoard64(GameBoard gameBoard)
        {
            CLRBitBoard64 cbb = new CLRBitBoard64();

            for (int row = 0; row < gameBoard.Size; row++)
            {
                for (int col = 0; col < gameBoard.Size; col++)
                {
                    enumFigureType figType = gameBoard.GetField(row, col);
                    if (figType != enumFigureType.Nothing)
                    {
                        ConvertToBB64(cbb, new Position(row, col), figType, gameBoard.Size / 2);
                    }
                }
            } // for

            return cbb;
        }

        /// <summary>
        /// Converts the move list into bitboard move list
        /// </summary>
        public static List<CLRBitBoard> ConvertMoves(List<Move> moves, GameBoard gameBoard)
        {
            List<CLRBitBoard> clrBB = new List<CLRBitBoard>();

            foreach (Move move in moves)
            {
                clrBB.Add(ConvertMoveToBB(move, gameBoard.GetField(move.startPos), gameBoard.Size / 2));
            }

            return clrBB;
        }

        /// <summary>
        /// Converts the move list into bitboard move list
        /// </summary>
        public static List<CLRBitBoard64> ConvertMoves64(List<Move> moves, GameBoard gameBoard)
        {
            List<CLRBitBoard64> clrBB = new List<CLRBitBoard64>();

            foreach (Move move in moves)
            {
                clrBB.Add(ConvertMoveToBB64(move, gameBoard.GetField(move.startPos), gameBoard.Size / 2));
            }

            return clrBB;
        }

        /// <summary>
        /// Convert move to bitboard
        /// </summary>
        public static CLRBitBoard ConvertMoveToBB(Move move, enumFigureType figureType, int boardSize)
        {
            CLRBitBoard cbb = new CLRBitBoard();

            // convert start position BB
            ConvertToBB(cbb, move.startPos, figureType, boardSize);

            // convert finish position to BB
            Move lastMove = move;
            while (lastMove.nextMove != null)
                lastMove = lastMove.nextMove;

            // check conversion to king
            if (lastMove.convertedToKing == true)
                figureType = figureType == enumFigureType.WhiteMan ? enumFigureType.WhiteKing : enumFigureType.BlackKing;

            ConvertToBB(cbb, lastMove.endPos, figureType, boardSize);

            // convert jumped figures
            Move moveStep = move;
            while (moveStep != null)
            {
                if (moveStep.RemovingFigure == true)
                {
                    ConvertToBB(cbb, moveStep.removedFigurePlace, moveStep.removedFigure, boardSize);
                }

                moveStep = moveStep.nextMove;
            } // while

            return cbb;
        }

        /// <summary>
        /// Convert move to bitboard 64
        /// </summary>
        public static CLRBitBoard64 ConvertMoveToBB64(Move move, enumFigureType figureType, int boardSize)
        {
            CLRBitBoard64 cbb = new CLRBitBoard64();

            // convert start position BB
            ConvertToBB64(cbb, move.startPos, figureType, boardSize);

            // convert finish position to BB
            Move lastMove = move;
            while (lastMove.nextMove != null)
                lastMove = lastMove.nextMove;

            // check conversion to king
            if (lastMove.convertedToKing == true)
                figureType = figureType == enumFigureType.WhiteMan ? enumFigureType.WhiteKing : enumFigureType.BlackKing;

            // convert the last position
            ConvertToBB64(cbb, lastMove.endPos, figureType, boardSize);


            // convert jumped figures
            Move moveStep = move;
            while (moveStep != null)
            {
                if (moveStep.RemovingFigure == true)
                {
                    ConvertToBB64(cbb, moveStep.removedFigurePlace, moveStep.removedFigure, boardSize);
                }

                moveStep = moveStep.nextMove;
            } // while

            return cbb;
        }

        /// <summary>
        /// Convert figure to bitboard
        /// </summary>
        private static void ConvertToBB(CLRBitBoard cbb, Position pos, enumFigureType figureType, int boardSize)
        {
            switch (figureType)
            {
                case enumFigureType.WhiteMan:
                    cbb.wm ^= ConvertToBB(pos, boardSize);
                    break;
                case enumFigureType.BlackMan:
                    cbb.bm ^= ConvertToBB(pos, boardSize);
                    break;
                case enumFigureType.WhiteKing:
                    cbb.wk ^= ConvertToBB(pos, boardSize);
                    break;
                case enumFigureType.BlackKing:
                    cbb.bk ^= ConvertToBB(pos, boardSize);
                    break;
            } // switch
        }

        /// <summary>
        /// Convert figure to bitboard
        /// </summary>
        private static void ConvertToBB64(CLRBitBoard64 cbb, Position pos, enumFigureType figureType, int boardSize)
        {
            switch (figureType)
            {
                case enumFigureType.WhiteMan:
                    cbb.wm ^= ConvertToBB64(pos, boardSize);
                    break;
                case enumFigureType.BlackMan:
                    cbb.bm ^= ConvertToBB64(pos, boardSize);
                    break;
                case enumFigureType.WhiteKing:
                    cbb.wk ^= ConvertToBB64(pos, boardSize);
                    break;
                case enumFigureType.BlackKing:
                    cbb.bk ^= ConvertToBB64(pos, boardSize);
                    break;
            } // switch
        }

        /// <summary>
        /// returns into bitboard a given position
        /// </summary>
        private static uint ConvertToBB(Position pos, int boardSize) 
        {
            uint value = default(uint);

            int shift = pos.Row * boardSize;
            if (pos.Col % 2 == 0)
                shift += pos.Col / 2;
            else
                shift += (pos.Col - 1) / 2;

            value = (uint)1 << shift;
            return value;
        }

        /// <summary>
        /// returns into bitboard a given position
        /// </summary>
        private static ulong ConvertToBB64(Position pos, int boardSize)
        {
            ulong value = default(ulong);

            int shift = pos.Row * boardSize;
            if (pos.Col % 2 == 0)
                shift += pos.Col / 2;
            else
                shift += (pos.Col - 1) / 2;

            value = (ulong)1 << shift;
            return value;
        }      
    }
}
